home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / gdevpdfj.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  10.9 KB  |  394 lines

  1. /* Copyright (C) 2000 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. /*$Id: gdevpdfj.c,v 1.5 2000/09/19 19:00:17 lpd Exp $ */
  20. /* Image-writing utilities for pdfwrite driver */
  21. #include "memory_.h"
  22. #include "string_.h"
  23. #include "gx.h"
  24. #include "gserrors.h"
  25. #include "gdevpdfx.h"
  26. #include "gdevpdfg.h"
  27. #include "gdevpdfo.h"
  28. #include "gxcspace.h"
  29. #include "gsiparm4.h"
  30.  
  31. #define CHECK(expr)\
  32.   BEGIN if ((code = (expr)) < 0) return code; END
  33.  
  34. /* GC descriptors */
  35. public_st_pdf_image_writer();
  36.  
  37. /* ---------------- Image stream dictionaries ---------------- */
  38.  
  39. const pdf_image_names_t pdf_image_names_full = {
  40.     { PDF_COLOR_SPACE_NAMES },
  41.     { PDF_FILTER_NAMES },
  42.     PDF_IMAGE_PARAM_NAMES
  43. };
  44. const pdf_image_names_t pdf_image_names_short = {
  45.     { PDF_COLOR_SPACE_NAMES_SHORT },
  46.     { PDF_FILTER_NAMES_SHORT },
  47.     PDF_IMAGE_PARAM_NAMES_SHORT
  48. };
  49.  
  50. /* Store the values of image parameters other than filters. */
  51. /* pdev is used only for updating procsets. */
  52. /* pcsvalue is not used for masks. */
  53. private int
  54. pdf_put_pixel_image_values(cos_dict_t *pcd, gx_device_pdf *pdev,
  55.                const gs_pixel_image_t *pim,
  56.                const gs_color_space *pcs,
  57.                const pdf_image_names_t *pin,
  58.                const cos_value_t *pcsvalue)
  59. {
  60.     int num_components;
  61.     float indexed_decode[2];
  62.     const float *default_decode = NULL;
  63.     int code;
  64.  
  65.     if (pcs) {
  66.     CHECK(cos_dict_put_c_key(pcd, pin->ColorSpace, pcsvalue));
  67.     pdf_color_space_procsets(pdev, pcs);
  68.     num_components = gs_color_space_num_components(pcs);
  69.     if (gs_color_space_get_index(pcs) == gs_color_space_index_Indexed) {
  70.         indexed_decode[0] = 0;
  71.         indexed_decode[1] = (1 << pim->BitsPerComponent) - 1;
  72.         default_decode = indexed_decode;
  73.     }
  74.     } else
  75.     num_components = 1;
  76.     CHECK(cos_dict_put_c_key_int(pcd, pin->Width, pim->Width));
  77.     CHECK(cos_dict_put_c_key_int(pcd, pin->Height, pim->Height));
  78.     CHECK(cos_dict_put_c_key_int(pcd, pin->BitsPerComponent,
  79.                  pim->BitsPerComponent));
  80.     {
  81.     int i;
  82.  
  83.     for (i = 0; i < num_components * 2; ++i)
  84.         if (pim->Decode[i] !=
  85.         (default_decode ? default_decode[i] : i & 1)
  86.         )
  87.         break;
  88.     if (i < num_components * 2) {
  89.         cos_array_t *pca =
  90.         cos_array_alloc(pdev, "pdf_put_pixel_image_values(decode)");
  91.  
  92.         if (pca == 0)
  93.         return_error(gs_error_VMerror);
  94.         for (i = 0; i < num_components * 2; ++i)
  95.         CHECK(cos_array_add_real(pca, pim->Decode[i]));
  96.         CHECK(cos_dict_put_c_key_object(pcd, pin->Decode,
  97.                         COS_OBJECT(pca)));
  98.     }
  99.     }
  100.     if (pim->Interpolate)
  101.     CHECK(cos_dict_put_c_strings(pcd, pin->Interpolate, "true"));
  102.     return 0;
  103. }
  104. int
  105. pdf_put_image_values(cos_dict_t *pcd, gx_device_pdf *pdev,
  106.              const gs_pixel_image_t *pic,
  107.              const pdf_image_names_t *pin,
  108.              const cos_value_t *pcsvalue)
  109. {
  110.     const gs_color_space *pcs = pic->ColorSpace;
  111.     int code;
  112.  
  113.     switch (pic->type->index) {
  114.     case 1: {
  115.     const gs_image1_t *pim = (const gs_image1_t *)pic;
  116.  
  117.     if (pim->ImageMask) {
  118.         CHECK(cos_dict_put_c_strings(pcd, pin->ImageMask, "true"));
  119.         pdev->procsets |= ImageB;
  120.         pcs = NULL;
  121.     }
  122.     }
  123.     break;
  124.     case 3: {
  125.     /*
  126.      * Clients must treat this as a special case: they must call
  127.      * pdf_put_image_values for the MaskDict separately, and must
  128.      * add the Mask entry to the main image stream (dictionary).
  129.      */
  130.     /*const gs_image3_t *pim = (const gs_image3_t *)pic;*/
  131.     }
  132.     break;
  133.     case 4: {
  134.     const gs_image4_t *pim = (const gs_image4_t *)pic;
  135.     int num_components = gs_color_space_num_components(pcs);
  136.     cos_array_t *pca =
  137.         cos_array_alloc(pdev, "pdf_put_image_values(mask)");
  138.     int i;
  139.     
  140.     if (pca == 0)
  141.         return_error(gs_error_VMerror);
  142.     for (i = 0; i < num_components; ++i) {
  143.         int lo, hi;
  144.  
  145.         if (pim->MaskColor_is_range)
  146.         lo = pim->MaskColor[i * 2], hi = pim->MaskColor[i * 2 + 1];
  147.         else
  148.         lo = hi = pim->MaskColor[i];
  149.         CHECK(cos_array_add_int(pca, lo));
  150.         CHECK(cos_array_add_int(pca, hi));
  151.     }
  152.     CHECK(cos_dict_put_c_key_object(pcd, "/Mask", COS_OBJECT(pca)));
  153.     }
  154.     break;
  155.     default:
  156.     return_error(gs_error_rangecheck);
  157.     }
  158.     return pdf_put_pixel_image_values(pcd, pdev, pic, pcs, pin, pcsvalue);
  159. }
  160.  
  161. /* Store filters for an image. */
  162. /* Currently this only saves parameters for CCITTFaxDecode. */
  163. int
  164. pdf_put_image_filters(cos_dict_t *pcd, gx_device_pdf *pdev,
  165.               const psdf_binary_writer * pbw,
  166.               const pdf_image_names_t *pin)
  167. {
  168.     return pdf_put_filters(pcd, pdev, pbw->strm, &pin->filter_names);
  169. }
  170.  
  171. /* ---------------- Image writing ---------------- */
  172.  
  173. /*
  174.  * Fill in the image parameters for a device space bitmap.
  175.  * PDF images are always specified top-to-bottom.
  176.  * data_h is the actual number of data rows, which may be less than h.
  177.  */
  178. void
  179. pdf_make_bitmap_matrix(gs_matrix * pmat, int x, int y, int w, int h,
  180.                int h_actual)
  181. {
  182.     pmat->xx = w;
  183.     pmat->xy = 0;
  184.     pmat->yx = 0;
  185.     pmat->yy = -h_actual;
  186.     pmat->tx = x;
  187.     pmat->ty = y + h;
  188. }
  189.  
  190. /*
  191.  * Put out the gsave and matrix for an image.  y_scale adjusts the matrix
  192.  * for images that end prematurely.
  193.  */
  194. void
  195. pdf_put_image_matrix(gx_device_pdf * pdev, const gs_matrix * pmat,
  196.              floatp y_scale)
  197. {
  198.     gs_matrix imat;
  199.  
  200.     gs_matrix_translate(pmat, 0.0, 1.0 - y_scale, &imat);
  201.     gs_matrix_scale(&imat, 1.0, y_scale, &imat);
  202.     pdf_put_matrix(pdev, "q ", &imat, "cm\n");
  203. }
  204.  
  205. /* Put out a reference to an image resource. */
  206. int
  207. pdf_do_image(gx_device_pdf * pdev, const pdf_resource_t * pres,
  208.          const gs_matrix * pimat, bool in_contents)
  209. {
  210.     if (in_contents) {
  211.     int code = pdf_open_contents(pdev, PDF_IN_STREAM);
  212.  
  213.     if (code < 0)
  214.         return code;
  215.     }
  216.     if (pimat) {
  217.     /* Adjust the matrix to account for short images. */
  218.     const pdf_x_object_t *const pxo = (const pdf_x_object_t *)pres;
  219.     double scale = (double)pxo->data_height / pxo->height;
  220.  
  221.     pdf_put_image_matrix(pdev, pimat, scale);
  222.     }
  223.     pprintld1(pdev->strm, "/R%ld Do\nQ\n", pdf_resource_id(pres));
  224.     return 0;
  225. }
  226.  
  227. /* ------ Begin / finish ------ */
  228.  
  229. /*
  230.  * Begin writing an image, creating the resource if not in-line and
  231.  * pres == 0, and setting up the binary writer.
  232.  */
  233. int
  234. pdf_begin_write_image(gx_device_pdf * pdev, pdf_image_writer * piw,
  235.               gx_bitmap_id id, int w, int h, pdf_resource_t *pres,
  236.               bool in_line)
  237. {
  238.     /* Patch pdev->strm so the right stream gets into the writer. */
  239.     stream *save_strm = pdev->strm;
  240.     int code;
  241.  
  242.     if (in_line) {
  243.     piw->pres = 0;
  244.     piw->pin = &pdf_image_names_short;
  245.     piw->data = cos_stream_alloc(pdev, "pdf_begin_image_data");
  246.     if (piw->data == 0)
  247.         return_error(gs_error_VMerror);
  248.     piw->end_string = " Q";
  249.     } else {
  250.     pdf_x_object_t *pxo;
  251.     cos_stream_t *pcos;
  252.  
  253.     if (pres == 0) {
  254.         code = pdf_alloc_resource(pdev, resourceXObject, id, &piw->pres,
  255.                       0L);
  256.         if (code < 0)
  257.         return code;
  258.         cos_become(piw->pres->object, cos_type_stream);
  259.     } else {
  260.         /* Resource already allocated (Mask for ImageType 3 image). */
  261.         piw->pres = pres;
  262.     }
  263.     piw->pres->rid = id;
  264.     piw->pin = &pdf_image_names_full;
  265.     pxo = (pdf_x_object_t *)piw->pres;
  266.     pcos = (cos_stream_t *)pxo->object;
  267.     CHECK(cos_dict_put_c_strings(cos_stream_dict(pcos), "/Subtype",
  268.                      "/Image"));
  269.     pxo->width = w;
  270.     pxo->height = h;
  271.     /* Initialize data_height for the benefit of copy_{mono,color}. */
  272.     pxo->data_height = h;
  273.     piw->data = pcos;
  274.     }
  275.     piw->height = h;
  276.     pdev->strm = pdev->streams.strm;
  277.     code = psdf_begin_binary((gx_device_psdf *) pdev, &piw->binary);
  278.     pdev->strm = save_strm;
  279.     return code;
  280. }
  281.  
  282. /* Begin writing the image data, setting up the dictionary and filters. */
  283. int
  284. pdf_begin_image_data(gx_device_pdf * pdev, pdf_image_writer * piw,
  285.              const gs_pixel_image_t * pim, const cos_value_t *pcsvalue)
  286. {
  287.     cos_dict_t *pcd = cos_stream_dict(piw->data);
  288.     int code = pdf_put_image_values(pcd, pdev, pim, piw->pin, pcsvalue);
  289.  
  290.     if (code >= 0)
  291.     code = pdf_put_image_filters(pcd, pdev, &piw->binary, piw->pin);
  292.     if (code < 0) {
  293.     if (!piw->pres)
  294.         COS_FREE(piw->data, "pdf_begin_image_data");
  295.     piw->data = 0;
  296.     }
  297.     return code;
  298. }
  299.  
  300. /* Finish writing the binary image data. */
  301. int
  302. pdf_end_image_binary(gx_device_pdf *pdev, pdf_image_writer *piw, int data_h)
  303. {
  304.     long pos = stell(pdev->streams.strm);  /* piw->binary.target */
  305.     int code;
  306.  
  307.     psdf_end_binary(&piw->binary);
  308.     code = cos_stream_add_since(piw->data, pos);
  309.     if (code < 0)
  310.     return code;
  311.     /* If the image ended prematurely, update the Height. */
  312.     if (data_h != piw->height)
  313.     code = cos_dict_put_c_key_int(cos_stream_dict(piw->data),
  314.                       piw->pin->Height, data_h);
  315.     return code;
  316. }
  317.  
  318. /*
  319.  * Finish writing an image.  If in-line, write the BI/dict/ID/data/EI and
  320.  * return 1; if a resource, write the resource definition and return 0.
  321.  */
  322. int
  323. pdf_end_write_image(gx_device_pdf * pdev, pdf_image_writer * piw)
  324. {
  325.     pdf_resource_t *pres = piw->pres;
  326.  
  327.     if (pres) {            /* image resource */
  328.     if (!pres->named) {    /* named objects are written at the end */
  329.         cos_write_object(pres->object, pdev);
  330.         cos_release(pres->object, "pdf_end_write_image");
  331.     }
  332.     return 0;
  333.     } else {            /* in-line image */
  334.     stream *s = pdev->strm;
  335.  
  336.     pputs(s, "BI\n");
  337.     cos_stream_elements_write(piw->data, pdev);
  338.     pputs(s, (pdev->binary_ok ? "ID " : "ID\n"));
  339.     cos_stream_contents_write(piw->data, pdev);
  340.     pprints1(s, "\nEI%s\n", piw->end_string);
  341.     COS_FREE(piw->data, "pdf_end_write_image");
  342.     return 1;
  343.     }
  344. }
  345.  
  346. /* ------ Copy data ------ */
  347.  
  348. /* Copy the data for a mask or monobit bitmap. */
  349. int
  350. pdf_copy_mask_bits(stream *s, const byte *base, int sourcex, int raster,
  351.            int w, int h, byte invert)
  352. {
  353.     int yi;
  354.  
  355.     for (yi = 0; yi < h; ++yi) {
  356.     const byte *data = base + yi * raster + (sourcex >> 3);
  357.     int sbit = sourcex & 7;
  358.  
  359.     if (sbit == 0) {
  360.         int nbytes = (w + 7) >> 3;
  361.         int i;
  362.  
  363.         for (i = 0; i < nbytes; ++data, ++i)
  364.         sputc(s, *data ^ invert);
  365.     } else {
  366.         int wleft = w;
  367.         int rbit = 8 - sbit;
  368.  
  369.         for (; wleft + sbit > 8; ++data, wleft -= 8)
  370.         sputc(s, ((*data << sbit) + (data[1] >> rbit)) ^ invert);
  371.         if (wleft > 0)
  372.         sputc(s, ((*data << sbit) ^ invert) &
  373.               (byte) (0xff00 >> wleft));
  374.     }
  375.     }
  376.     return 0;
  377. }
  378.  
  379. /* Copy the data for a colored image (device pixels). */
  380. int
  381. pdf_copy_color_bits(stream *s, const byte *base, int sourcex, int raster,
  382.             int w, int h, int bytes_per_pixel)
  383. {
  384.     int yi;
  385.  
  386.     for (yi = 0; yi < h; ++yi) {
  387.     uint ignore;
  388.  
  389.     sputs(s, base + sourcex * bytes_per_pixel + yi * raster,
  390.           w * bytes_per_pixel, &ignore);
  391.     }
  392.     return 0;
  393. }
  394.